我根據文章內容製作了 Nuget 套件。
PM> Install-Package PdfTemplate.iTextSharp.LGPLv2
這個套件內部使用 iTextSharp.LGPLv2 生成 pdf 文件,因此它的授權較 iTextSharp 和 iText 7 更寬鬆。
用法可以參考 Github 內容。
https://github.com/fysh711426/PdfTemplate.iTextSharp.LGPLv2
做報表常會用到 PDF 套版,套版的類型很多,文字、顏色、圖片、Radio、CheckBox、等等...,有時候還要分頁,所以想把這些需求整理起來。
範本一般會用 Word
畫出表格後 匯出成 PDF
,再用 Adobe Acrobat
將需要填入資料的地方加入表格元件。
下圖為 Word 製作的基本資料表格。
將其匯出成 PDF,再用 Adobe Acrobat 開啟,點選右上角的 工具
開啟選單,然後選擇 表格
內的 編輯
。
第一次編輯會詢問 是否自動偵測表格
,這裡選 是
可以讓 Acrobat 自動偵測並建立表格,剩下的再手動調整。
點擊欄位兩下開啟 內容視窗
,將 名稱
改成給程式對應的欄位名稱。
性別欄位只有男或女且單選,所以用 RadioButton
,點選右上角新增欄位
,選擇選項按鈕
。
RadioButton 為同群組單選的元件,其 名稱
為群組,選項按鈕選擇
為被選取的值,這裡新增男女兩個 RadioButton,將名稱改為 SexGroup
,選項按鈕選擇分別改為 Male
和 Female
。
興趣欄位可多選,所以用 CheckBox
,點選右上角 新增欄位
,選擇 核取框
。
CheckBox 不像 RadioButton 有 群組
概念,每個 CheckBox 都有自己的名稱,判斷是否被勾選,要看內容視窗裡的 轉存值
,預設為 是
,只要程式丟過來的值等於 轉存值
,CheckBox 就會被勾選。
圖片套版會使用 按鈕
元件,將背景色設為 白色
,利用按鈕的 icon
來替換圖片。
開啟內容視窗改變背景色。
Barcode 部分不用更改,使用 文字欄位
即可。
完整程式太長就不貼上來,下方分享常用功能。
第一頁
第二頁
會用到 iTextSharp
可用 Nuget 安裝。
//可以是任何 Stream 類型 (MemoryStream、FileStream、OutputStream)
var stream = new MemoryStream();
//建立文件
using (var doc = new Document())
{
using (var writer = PdfWriter.GetInstance(doc, stream))
{
doc.Open();
//操作 PDF ...
doc.Close();
}
}
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader("範本檔路徑"))
{
using (var stamper = new PdfStamper(reader, ms))
{
//取得表單
var form = stamper.AcroFields;
//套入文字
form.SetField("Name", "王小明");
}
}
}
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader("範本檔路徑"))
{
using (var stamper = new PdfStamper(reader, ms))
{
//取得表單
var form = stamper.AcroFields;
//套入文字
form.SetField("Name", "王小明");
//套入顏色
var color = "#FF0000"; //紅色
var baseColor = new BaseColor(System.Drawing.ColorTranslator.FromHtml(color));
form.SetFieldProperty("Name", "textcolor", baseColor, null);
}
}
}
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader("範本檔路徑"))
{
using (var stamper = new PdfStamper(reader, ms))
{
//取得表單
var form = stamper.AcroFields;
//RadioButton
form.SetField("Group", "男", true);
//CheckBox
form.SetField("Name", "是", true);
}
}
}
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader("範本檔路徑"))
{
using (var stamper = new PdfStamper(reader, ms))
{
//取得表單
var form = stamper.AcroFields;
//取得圖片
var image = iTextSharp.text.Image.GetInstance("圖片檔路徑");
//取得按鈕元件
var pushbuttonField = form.GetNewPushbuttonFromField("Name");
//指定為 ICON
pushbuttonField.Layout = PushbuttonField.LAYOUT_ICON_ONLY;
//圖片等比縮放
pushbuttonField.ProportionalIcon = true;
pushbuttonField.Image = image;
//取代原按鈕
form.ReplacePushbuttonField("Name", pushbuttonField.Field);
}
}
}
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader("範本檔路徑"))
{
using (var stamper = new PdfStamper(reader, ms))
{
//取得表單
var form = stamper.AcroFields;
//取得欄位位置資訊
var fieldPosition = form.GetFieldPositions("Name")[0];
var pdfContentByte = stamper.GetOverContent(fieldPosition.page);
var barcode = new Barcode39();
//barcode 內容
barcode.Code = "123456789";
//顯示文字是否前後加上星號
barcode.StartStopText = false;
//條碼線最小寬度
barcode.X = 0.8f;
//設置墨水擴散量,從每個條碼線中減去該值
barcode.InkSpreading = 0f;
//為某些類型保留條碼線的乘數
barcode.N = 2f;
//字體大小
barcode.Size = 10f;
//文本和條形碼之間的距離
barcode.Baseline = 10f;
//barcode 高度
barcode.BarHeight = 20f;
barcode.GenerateChecksum = false;
barcode.ChecksumText = false;
//產生 barcode 圖片
var image = barcode.CreateImageWithBarcode(pdfContentByte, BaseColor.BLACK, BaseColor.BLACK);
var rect = fieldPosition.position;
//設定圖片座標,以欄位的左下角為原點
image.SetAbsolutePosition(rect.Left, rect.Bottom);
pdfContentByte.AddImage(image);
}
}
}
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader("範本檔路徑"))
{
using (var stamper = new PdfStamper(reader, ms))
{
//取得表單
var form = stamper.AcroFields;
//新增段落
var paragraph = new Paragraph("abc");
//取得欄位位置資訊
var fieldPositions = form.GetFieldPositions("Name");
//設定行距
paragraph.Leading = 30;
//設定第一列縮排
paragraph.FirstLineIndent = 24;
//設定對齊方式
paragraph.Alignment = iTextSharp.text.Element.ALIGN_JUSTIFIED;
foreach (var position in fieldPositions)
{
var pdfContentByte = stamper.GetOverContent(position.page);
var columnText = new ColumnText(pdfContentByte);
//ColumnText 呼叫 AddElement 後,自動由 Text 模式轉為 Composite 模式
columnText.AddElement(paragraph);
//設定 ColumnText 邊界
columnText.SetSimpleColumn(position.position.Left, position.position.Bottom, position.position.Right, position.position.Top);
columnText.Go();
}
}
}
}
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader("範本檔路徑"))
{
using (var stamper = new PdfStamper(reader, ms))
{
//取得表單
var form = stamper.AcroFields;
//取得欄位位置資訊
var fieldPositions = form.GetFieldPositions("");
foreach (var position in fieldPositions)
{
var pdfContentByte = stamper.GetUnderContent(position.page);
pdfContentByte.BeginText();
var baseFont = BaseFont.CreateFont("字型檔路徑", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
//設定字型和字體大小
pdfContentByte.SetFontAndSize(baseFont, 120);
//設定字體顏色
pdfContentByte.SetRGBColorFill(210, 210, 210);
//設定浮水印透明度
pdfContentByte.SetGState(new PdfGState
{
FillOpacity = 0.6f, //背景
StrokeOpacity = 0.6f //文字
});
//取得當前頁面的位置資訊
var rect = reader.GetPageSizeWithRotation(position.page);
var x = (rect.Right + rect.Left) / 2; //取得頁面 x 軸中心座標
var y = (rect.Bottom + rect.Top) / 2; //取得頁面 y 軸中心座標
//設定浮水印
pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "浮水印", x, y, 45);
pdfContentByte.EndText();
}
}
}
}
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader("範本檔路徑"))
{
using (var stamper = new PdfStamper(reader, ms))
{
//表單扁平化,防止表單編輯
stamper.FormFlattening = true;
}
}
}
var baseFont1 = BaseFont.CreateFont("字型檔1路徑", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
var baseFont2 = BaseFont.CreateFont("字型檔2路徑", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
//表單設定字型
stamper.AcroFields.AddSubstitutionFont(baseFont1);
stamper.AcroFields.AddSubstitutionFont(baseFont2);
//段落設定字型
var font1 = new Font(baseFont1, 12f, Font.NORMAL);
var font2 = new Font(baseFont2, 12f, Font.NORMAL);
var selector = new iTextSharp.text.pdf.FontSelector();
selector.AddFont(font1);
selector.AddFont(font2);
var paragraph = new iTextSharp.text.Paragraph();
paragraph.Add(selector.Process("abc一二三"));
//要合併的多個 PDF 文件
var files = new List<byte[]>();
using (var doc = new Document())
{
using (var writer = PdfWriter.GetInstance(doc, stream))
{
doc.Open();
var contentByte = writer.DirectContent;
foreach(var file in files)
{
using (var reader = new PdfReader(file))
{
for (var i = 1; i <= reader.NumberOfPages; i++)
{
//設定頁面大小為當前範本的頁面的大小
doc.SetPageSize(reader.GetPageSize(i));
//產生新頁面
doc.NewPage();
//將 Reader 轉為 PdfImportedPage
var newPage = writer.GetImportedPage(reader, i);
//插入新頁面
contentByte.AddTemplate(newPage, 0, 0);
}
//釋放 reader
writer.FreeReader(reader);
}
}
doc.Close();
}
}
使用ASP .NET (C#) 產生PDF檔的好幫手—iTextSharp library (上)
c#使用itextsharp输出pdf(动态填充表单内容,显示中文)
How to change the text color of an AcroForm field?
使用iTextSharp進行PDF檔案套版
iTextSharp Fill Pdf Form Image Field
Code 39/128 Barcode Image Generator
[iTextSharp学习笔记]在指定的位置上添加文本
CSharp - 在每個頁面上,使用水印創建 C# itextsharp PDF
如何使用itextsharp将表单字段添加到现有的pdf中?
Missing character in custom font
itextsharp - 如何使用iTextSharp組合多個不包括分頁符的PDF文件?
這套件我也有用過,
還不錯用,
不過我是拿來做表格的。
表格也可以套板
學號 | 姓名 |
---|---|
Id1 | Name1 |
Id2 | Name2 |
... | ... |
在範本裡面先把整個表格排滿,哈哈。 | |
因為很懶所以都會想用範本做,可以省很多工。 |
前提是你會常用到那些範本,
要不然做範本只在一個地方用到也沒有意義 @@
恩恩,還是要看需求使用。
大大的文章真是幫助極大,目前接手的案子就是需要用到填表格的功能,過去是使用讀取excel表填寫再轉PDF輸出,看到這篇之後終於有其他解法啦,謝謝分享
表單如果欄位固定很適合用此方法,不怕客戶改樣式、開發快速
缺點是欄位無法動態、產生的檔案較大
不過我覺得優點還是更多些
請問如果用這種方式,是不是需要使用Acrobat Pro DC才能規劃表格呢?
只要支援表格編輯的 PDF 軟體都可以
最近專案也有將資料讀入PDF匯出的需求,除了iTextSharp還有搜尋到一款ironpdf,好像也蠻好用的版主有使用過嗎??
這套看起來偏 Html 轉 PDF
以前試過的 Html 轉 PDF 套件一般都會跑版
所以還是喜歡套版或用刻的
不好意思,最近正在學習MVC,正好需要用到此功能,可是一直出現問題,並且上網爬文都沒有找到解決方案,請問版主大大可以幫忙看一下嗎, 謝謝~~
程式碼
public void DownloadPdf(int id)
{
//然後把值傳進Post_ed_details裡
var classes = db.ClassDetails.Where(m => m.Class_Id == id).FirstOrDefault();
//可以是任何 Stream 類型 (MemoryStream、FileStream、OutputStream)
var stream = new MemoryStream();
DateTime nowdate = DateTime.Now;
//下拉式選單把數字轉成文字
int starttimeid = (int)classes.Class_time_start;
int endtimeid = (int)classes.Class_time_end;
int departmentid = (int)classes.Class_department;
var startTimes = db.ed_Create_time.Where(m => m.ed_Time_id == starttimeid).FirstOrDefault();
var endTimes = db.ed_Create_time.Where(m => m.ed_Time_id == endtimeid).FirstOrDefault();
var departments = db.ed_Create_department.Where(m => m.department_id == departmentid).FirstOrDefault();
classes.ed_Time_namestart = startTimes.ed_Time_value;
classes.ed_Time_nameend = endTimes.ed_Time_value;
classes.department_name = departments.department_value;
//建立文件
using (var doc = new Document())
{
using (var writer = PdfWriter.GetInstance(doc, stream))
{
doc.Open();
//操作 PDF ...
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader(@"D:\123.pdf"))
{
using (var stamper = new PdfStamper(reader, ms))
{
//取得表單
var form = stamper.AcroFields;
//套入文字
form.SetField("department", classes.department_name);
form.SetField("em_id", classes.Em_Id);
form.SetField("em_name", classes.Em_Name);
form.SetField("class_name", classes.Class_Name);
form.SetField("class_place", classes.Class_Place);
form.SetField("Class_date_start", classes.Class_date_start);
form.SetField("Class_date_end", classes.Class_date_end);
form.SetField("Class_time_start", classes.ed_Time_namestart);
form.SetField("Class_time_end", classes.ed_Time_nameend);
form.SetField("duration", classes.Class_Duration);
form.SetField("cost", classes.Class_Cost);
form.SetField("organizer", classes.Class_Organizer);
}
}
}
doc.Close();
}
}
}
public ActionResult pdf(int id)
{
DownloadPdf(id);
return View();
}
using (var ms = new MemoryStream())
要放在 doc 之外
using (var doc = new Document())
謝謝你上面的解答,我已經可以輸出成一個pdf,只是裡面的表格無法正常顯示
開啟pdf看到的畫面↓
像是這張圖只有用滑鼠點才會顯示↓
請問此問題要如何解決,謝謝~
試試在 stamper 的最後加上
stamper.FormFlattening = true;
會全部變成空白
可能是缺少字型檔。
var baseFont = BaseFont.CreateFont("字型路徑.ttf",
BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
stamper.AcroFields.AddSubstitutionFont(baseFont);
原來是我沒看清楚 謝謝大大時間幫我解決問題 感謝~
我根據文章內容製作了套件
方便大家使用,可以參考看看
https://github.com/fysh711426/PdfTemplate.iTextSharp.LGPLv2
如果你要做分頁、多範本、插入圖片或浮水印等,推薦使用